整合python高产与C/C++高效的优势
利用C或Python已有功能服务彼此
python作为胶水语言整合或者被整合到各类独立程序
扩展:python中调用C/C++编写的库
提升关键代码性能
引入C语言成熟功能库
以python为主程序,C通过.dll/.so形式使用
方式:
ctypes
调用DLL或共享库的python功能函数库,标准库API
https://docs.python.org/3.7/library/ctypes.html
通过一个python标准库实现python扩展
C语言功能编成.dll或.so库,加载库及调用函数,API
C语言独立编程,python使用库调用接口函数
CFFI (C Foreign Function Interface for Python)
在python中直接使用C函数的方式
第三方库 pip install cffi
https://cffi.readthedocs.io/en/latest/
思路类似ctypes,使用API扩展C程序,也可以直接混合编程
关注C函数的访问接口,而不是库函数,构建API
C语言独立编程,python用CFFI扩展,学习成本低。
- 功能接口
与C语言数据类型相关的接口 | 描述 |
---|---|
ffi.NULL | 相当于常量值NULL |
ffi.new(cdecl) | 数组或指针的生成,new(‘x*’)或new(‘x[n]’) |
ffi.cast(ctype, value) | C数据类型的声明,ctype是类型名,value是变量名 cast(‘int’, x) |
ffi.string(cdata) | 从cdata类型中返回一个Python字符串 |
ffi.unpack(cdata, length) | 从cdata数组中获取特定长度,返回一个Python字符串或列表 |
与数据大小相关的接口 | 描述 |
---|---|
ffi.typeof(ctype) | 返回ctype的长度 |
ffi.sizeof(object) | 返回object对象的长度 |
ffi.alignof(ctype) | 返回ctype或对象的长度 |
与调用相关的接口 | 描述 |
---|---|
ffi.dlopen(libpath) | 打开动态链接库并建立一个句柄 |
ffi.dlclose(lib) | 关闭动态链接库并释放句柄 |
ffi.cdef(str) | str指明Python中需要使用的C类型、函数等声明 |
与内存操作相关的接口 | 描述 |
---|---|
ffi.memmove(dst, src, n) | 从src向dst拷贝n直接内容,src和dst都是python变量 |
简单应用
1
2
3
4
5
6
7
8
9
10
11
12
13/* 可编译为.dll的C语言代码 mxmul.h */
DLLIMPORT int *mxmul(int nrow, int nk, int ncol, int mx1[][nk], int mx2[][ncol]);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48/* 可编译为.dll的C语言代码 mxmul.c */
/* Parameters: nrow, nk, ncol, mx1, mx2 */
DLLIMPORT int *mxmul(int nrow, int nk, int ncol, int mx1[][nk], int mx2[][ncol])
{
int x, i, j;
int *rst;
rst = malloc(sizeof(int) * nrow * ncol);
for(i = 0; i < nrow; i++)
{
for(j = 0; j < ncol; j++)
{
rst[i*ncol +j] =0;
for(x = 0; x < nk; x++)
{
rest[i*ncol +j] +=*(*(mx1+i)+x) * *(*(mx2+x)+j);
}
}
}
return rst;
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
{
switch(fdwReason)
{
case DLL_PROCESS_ATTACH:
{
break;
}
case DLL_PROCESS_DETACH:
{
break;
}
case DLL_THREAD_ATTACH:
{
break;
}
case DLL_THREAD_DETACH:
{
break;
}
}
}mxmul.c和mxmul.h 编译后可以得到mxmul.dll和mxmul32.dll
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42# 用来封装.dll的python模块 cmxmul.py
import array
from cffi import FFI
def cmxmul(nrow, nk, ncol, mx1, mx2):
ffi = FFI()
# 基本类型参数关联
c_nrow = ffi.cast('int', nrow)
c_nk = ffi.cast('int', nk)
c_ncol = ffi.cast('int', ncol)
# 列表类型参数关联
_mx1 = array.array('l')
_mx2 = array.array('l')
[_mx1.fromlist(x) for x in mx1 ]
[_mx2.fromlist(x) for x in mx2 ]
# 数据的内存拷贝
c_mx1 = ffi.new('int[]', len(_mx1))
c_mx2 = ffi.new('int[]', len(_mx2))
ffi.memmove(c_mx1, _mx1, ffi.sizeof(c_mx1))
ffi.memmove(c_mx2, _mx2, ffi.sizeof(c_mx2))
# 声明函数
ffi.cdef('''
int *mxmul(int nrow, int nk, int ncol, int *mx1, int *mx2);
''')
# 调用dll库
try :
# 64位计算机加载mxmul.dll
C = ffi.dlopen('mxmul.dll')
except :
# 32位计算机加载mxmul32.dll
C = ffi.dlopen('mxmul32.dll')
# 调用动态链接库中的函数
c_res = C.mxmul(c_nrow, c_nk, c_ncol, c_mx1, c_mx2)
#解包返回
return ffi.unpack(c_res, nrow * ncol1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17# 用来测试效果的python程序 test.py
from cmxmul import cmxmul
if __name__ == '__main__':
import time
nrow, nk, ncol = 500, 300, 500
mx1 = [[i for i in range(nk)] for j in range(nrow)]
mx2 = [[i for i in range(ncol)] for j in range(nk)]
start = time.perf_counter()
rst = cmxmul(nrow, nk, ncol, mx1, mx2)
end = time.perf_counter()
print('运行时间:%.4f秒' % (end - start))
'''
运行时间:0.3135秒
'''
Cython
实现python扩展的一种语言,第三方库。
通过一种简单的语言来实现python和C的接口
采用了Pyrex语法形式
采用C数据类型的python编程,实现混合编程
SWIG
一个将C/C++与脚本语言相整合的编译器,独立工具
通过一个编译器来实现python和C的接口
纯C/C++编程,通过编写接口变成python模块
独立C和python编程,重点在于编写接口(描述)
调用:python和C间以进程级别相互调用
模块间功能互用
以功能使用为目标
C/C++和python都是独立程序
方式:子进程或线程方式
Python 中调用C语言程序
1
2
3
4
5
6
7
8
9
10
11
12
13/* 待调用的c程序源码 */
int main(int argc, char **argv)
{
int a;
a = atoi(argv[1]);
printf("input x:%d\n", a);
printf("pow(x):%d\n", a*a);
return 0;
}
//编译成pow.exe1
2
3
4
5
6
7# xxx.py
import subprocess
subprocess.run(["pow.exe", "9"])
'''执行后的结果
input x:9
pow(x):81
'''subprocess.run()的参数可以是一个字符串或一个列表
如果是字符串,就是程序的名称
如果是列表,是程序名称和参数组成的列表
C语言中调用python程序
1
2
3
4# pow.py
import sys
print("input x:%d"%sys.argv[1])
print("pow(x):%d"%pow(int(sys.argv[1]),2))1
2
3
4
5
6
7
8/* test.c */
int main(){
system("python pow.py 9");
return 0;
}
//编译后运行system(char *cmd) 是C/C++下的标准函数,C89定义。将指令和参数以字符指针形式作为参数传递执行程序。
嵌入:C/C++中调用python程序
利用python高产
引入python成熟功能库
以C/C++为主程序,python通过源文件形式使用
方式:python/c API https://docs.python.org/3/c-api/
- 嵌入python语句:嵌入一个或多个python语句
- 嵌入python脚本:嵌入一个或多个python文件
- python/C API 需要加载python解释器以及加载python语句和脚本
头文件:python.h
函数:加载python解释器、嵌入python语句及脚本、数据类型转换等。
1 |
|
函数 | 描述 |
---|---|
Py_Initialize() | 初始化Python解释器,加载builtins、__main__、sys等 |
Py_Finalize() | 终结化python解释器,释放解释器占用的内存 |
PyRun_SimpleString(const char* cmd) | 在__main__模块中执行一句语句 如果main不存在则创建 |
PyRun_SimpleFile(FILE fp, const char fname) | 在C中调用一个Python文件 |
1 |
|